package com.glodon.paas.document.web.resource;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.glodon.paas.consts.StringConst;
import com.glodon.paas.document.api.bean.File;
import com.glodon.paas.document.service.FileService;
import com.glodon.paas.document.service.RecyclerService;
import com.glodon.paas.document.service.util.DocumentPrivilege;
import com.glodon.paas.dto.DataTansitionObject;
import com.glodon.paas.exception.PaasServerException;
import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.glodon.paas.exception.i18n.ErrorCode;
import com.glodon.paas.storage.ReadResult;
import com.glodon.paas.util.FileUtil;
import com.glodon.paas.web.resource.BaseResource;

public abstract class FileResource implements BaseResource {

    @Autowired
    private FileService     fileService;

    @Autowired
    private RecyclerService recyclerService;
    
    @Autowired
    private DocumentPrivilege documentPrivilege;

    // 暂时不考虑排序
    @GET
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    public List<File> getFiles(@Context
    HttpServletRequest request, @QueryParam("child")
    String child) {
        if (child == null) {
            throw PaasServerExceptionFactory.externalAPIException("please add [child] in query paramter.", null);
        }
        String userId = getUserId(request);

        return fileService.getFiles(userId, userId, null, null, false);
    }

    @GET
    @Path("/{filePath:.+}")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getFile(@Context HttpServletRequest request, @Context HttpServletResponse response,
                          @PathParam("filePath") String filePath, @QueryParam("meta") String meta,
                          @QueryParam("path") String path, @QueryParam("privilege") String privilege,
                          @QueryParam("child") String child, @QueryParam("revision") String revision,
                          @QueryParam("uploaded") String uploaded, @QueryParam("type") String type,
                          @QueryParam("rev") String rev) {
        if ((meta != null && child != null) || (meta != null && revision != null) || (meta != null && uploaded != null)
            || (child != null && revision != null) || (child != null && uploaded != null)
            || (revision != null && uploaded != null)) {
            throw PaasServerExceptionFactory.externalAPIException("too many paramters, [meta,child,revision,uploaded] just can be selected one or no.",
                                                                  null);
        }
        request.setAttribute("filePath", filePath);
        String userId = getUserId(request);
        filePath = (String) request.getAttribute("filePath");
        String fileId = "id".equalsIgnoreCase(type) ? filePath : fileService.getFileId(userId, filePath);
        if (privilege != null) {
            String[] pvs =  privilege.split(StringConst.SEPARATOR_COMMA);
            boolean owner=false;
            boolean sharer=false;
            boolean enter=false;
            boolean read=false;
            boolean write=false;
            boolean delete=false;
            for ( String pv : pvs){
                if(pv.trim().equalsIgnoreCase(StringConst.OWNER)){
                    owner = true;
                }
                else if(pv.trim().equalsIgnoreCase(StringConst.SHARER)){
                    sharer = true;
                }
                else if(pv.trim().equalsIgnoreCase(StringConst.ENTER)){
                    enter = true;
                }
                else if(pv.trim().equalsIgnoreCase(StringConst.READ)){
                    read = true;
                }
                else if(pv.trim().equalsIgnoreCase(StringConst.WRITE)){
                    write = true;
                }
                else if(pv.trim().equalsIgnoreCase(StringConst.DELETE)){
                    delete = true;
                }
            }
            return documentPrivilege.hasPrivilege(userId, fileId, enter, read, write, delete, owner, sharer);
        }else if (path != null) {
            return fileService.getPath(userId, fileId, false);
        }else if(meta != null) {
            return fileService.getFile(userId, fileId, false);
        } else if (child != null) {
            return fileService.getFiles(userId, fileId, null, null, false);
        } else if (revision != null) {
            return fileService.getRevisions(userId, fileId);
        } else if (uploaded != null) {
            return fileService.getUploadedBytes(fileId);
        } else {
            File file = fileService.getFile(userId, fileId, false);
            if (file.isFolder()) {
                response.addHeader("Content-Disposition",
                                   "attachment; filename=\""
                                           + FileUtil.encodeFileName(request, file.getName() + ".zip") + "\"");
                response.addHeader("zip", "true");
                try {
                    fileService.downloadFolder(userId, fileId, response.getOutputStream());
                } catch (PaasServerException de) {
                    throw de;
                } catch (Exception er) {
                    throw PaasServerExceptionFactory.systemException(er.getMessage(), er);
                }
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                response.setStatus(200);
                return null;
            } else {
                int num = StringUtils.isNumeric(rev) ? Integer.valueOf(rev) : -1;
                ReadResult rr = fileService.downloadFile(userId, fileId, num);
                return Response.ok(rr.getInputStream(), MediaType.APPLICATION_OCTET_STREAM_TYPE).header("Content-Length",
                                                                                                        Long.toString(rr.getLength())).header("Content-Disposition",
                                                                                                                                              "attachment; filename=\""
                                                                                                                                                      + FileUtil.encodeFileName(request,
                                                                                                                                                                                rr.getName())
                                                                                                                                                      + "\"").build();
            }
        }
    }

    @POST
    @Path("/{filePath:.+}")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.APPLICATION_JSON)
    public File createFile(@Context
    HttpServletRequest request, @PathParam("filePath")
    String filePath, @QueryParam("folder")
    String folder, @QueryParam("type")
    String type, @QueryParam("fileSize")
    String fileSize, @QueryParam("position")
    @DefaultValue("0")
    String position, InputStream inputFileStream) {
        String userId = getUserId(request);
        // create folder
        if (folder != null) {
            return fileService.createFolder(userId, filePath, userId);
        }
        if (!StringUtils.isNumeric(fileSize)) {
            fileSize = request.getHeader("Content-Length");
        }
        // upload file
        if (StringUtils.isNumeric(fileSize)) {
            if ("id".equalsIgnoreCase(type)) {
                // File file = fileService.getFile(userId, filePath);
                StringBuffer path = new StringBuffer();
                List<DataTansitionObject> names = fileService.getPath(userId, filePath);
                for (int i = 0; i < names.size(); i++) {
                    path.append(names.get(i).getName() + "/");
                }
                path.deleteCharAt(path.length() - 1);
                // path.append(file.getFullName());
                filePath = path.toString();
            }
            try {
                return fileService.uploadFile(userId, userId, filePath, Long.valueOf(position),
                                              Long.valueOf(fileSize), inputFileStream);
            } finally {
                if (inputFileStream != null) {
                    try {
                        inputFileStream.close();
                    } catch (IOException ignore) {
                    }
                }
            }
        } else {
            throw PaasServerExceptionFactory.validateException("fileSize in incorrect.", null).setErrorCode(ErrorCode.FILE_SIZE_INCORRECT);
        }
    }

    @DELETE
    @Path("/{filePath:.+}")
    @Produces(MediaType.TEXT_PLAIN)
    public String remove(@Context
    HttpServletRequest request, @PathParam("filePath")
    String filePath, @QueryParam("type")
    String type, @QueryParam("target")
    String target) {
        String userId = getUserId(request);
        String fileId = "id".equalsIgnoreCase(type) ? filePath : fileService.getFileId(userId, filePath);
        if ("recycler".equalsIgnoreCase(target)) {
            fileService.remove(userId, fileId);
        } else {
            recyclerService.remove(userId, fileId);
        }
        return StringConst.SUCCESS;
    }

    @PUT
    @Path("/{filePath:.+}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_PLAIN)
    public String rename(@Context
    HttpServletRequest request, @PathParam("filePath")
    String filePath, @QueryParam("type")
    String type, @QueryParam("name")
    String name) {
        String userId = getUserId(request);
        String fileId = "id".equalsIgnoreCase(type) ? filePath : fileService.getFileId(userId, filePath);
        fileService.rename(userId, fileId, name);
        return StringConst.SUCCESS;
    }
}
